package syR

import (
	"db2s/arg"
	"db2s/global"
	"db2s/go-log/log"
	"db2s/outPut"
	"db2s/pubM"
	"db2s/ref"
	"fmt"
	"os"
	"reflect"
	"strings"
	"time"
)

func syncBreakPointF(config arg.RulesS) bool {
	switch config.Sync.Breakpoint {
	case false:
		return true
	case true:
		return false
	}
	return false
}
func breakPointFuncMap() map[string]reflect.Value {
	return map[string]reflect.Value{"sync": reflect.ValueOf(syncBreakPointF)}
}
func getBreakPointStatus(config arg.RulesS) bool {
	if funcName, ok := breakPointFuncMap()[config.CheckMode]; ok {
		args := []reflect.Value{
			reflect.ValueOf(config),
		}
		l := funcName.Call(args)
		return l[0].Interface().(bool)
	}
	return false
}

func newXlsObject(baseDir string, config GlobalParametersConfig) {
	xlsFileName := fmt.Sprintf("%v/%v", baseDir, config.result.XlsV.XlsFileName)
	if !strings.Contains(xlsFileName, "/") {
		xlsFileName = fmt.Sprintf("./%v", xlsFileName)
	}
	xlsFile = outPut.NewFileOperations(outPut.Xls{
		FileName:  fmt.Sprintf("./%v.xlsx", xlsFileName),
		SheetName: []string{"terminal", "result", "miss"},
		Mode:      config.rules.CheckMode,
		Enroll:    []any{outPut.WorkSheetTerminal{}, outPut.WorkSheetResult{}, outPut.WorkSheetMiss{}},
		Safety:    config.result.XlsV.XlsSafetySwitch,
	})
}
func initTextData(baseDir string, config GlobalParametersConfig) (err error) {
	textFile = outPut.NewFileOperations(outPut.Tex{
		SheetName: []string{"terminal", "result", "miss"},
		Mode:      config.rules.CheckMode,
		Enroll:    []any{outPut.WorkSheetTerminal{Persistence: baseDir}, outPut.WorkSheetResult{Persistence: baseDir}, outPut.WorkSheetMiss{Persistence: baseDir}},
		Safety:    false,
	})
	if err = textFile.Head(); err != nil {
		log.ErrorLog().Error(fmt.Sprintf("Failed to write the TEXT header title. error is %v", err))
		return
	}
	return
}
func initXlsData(baseDir string, config GlobalParametersConfig) (err error) {
	newXlsObject(baseDir, config)
	if err = xlsFile.Create(); err != nil {
		log.ErrorLog().Error(fmt.Sprintf("Failed to create the XLS file. error is %v", err))
		return
	}
	if err = xlsFile.Head(); err != nil {
		log.ErrorLog().Error(fmt.Sprintf("Failed to write the XLS header title. error is %v", err))
		return
	}
	return
}
func initResultData(baseDir string, config GlobalParametersConfig) (err error) {
	//初始化输出目录result
	if !config.result.GeneralResult {
		log.MainLog().Warn(fmt.Sprintf("If the xls generation parameter is set to false, this step will be skipped."))
		return
	}
	log.MainLog().Info("Start initializing the Result data")
	baseDir = fmt.Sprintf("%v/xls", baseDir)
	if err = dirInit(baseDir); err != nil {
		log.ErrorLog().Error(fmt.Sprintf("The creation of the %v directory failed. error is %v", baseDir, err))
		return
	}
	if initXlsData(baseDir, config) != nil {
		return
	}
	if initTextData(baseDir, config) != nil {
		return
	}
	log.MainLog().Info(fmt.Sprintf("The result data initialization has been completed"))
	return
}
func initOtherResultFile(baseDir, name, mode string, config GlobalParametersConfig) (result ReadWriteFilePointS, err error) {
	log.MainLog().Info(fmt.Sprintf("Start initializing the TTY BAR file"))
	breakP = pubM.NewBreakObject(pubM.BreakPoint{
		FileName: fmt.Sprintf("result/breakPoint/%v/%v/%v", name, mode, global.BreakPointFileName),
		Truncate: getBreakPointStatus(config.rules),
	})
	if breakP.Read() != nil {
		return
	}
	log.MainLog().Info(fmt.Sprintf("Start initializing the parameterRecord file"))
	if result.ParameterRecord, err = os.OpenFile(fmt.Sprintf("result/%v", global.ParameterRecord), os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0664); err != nil {
		log.ErrorLog().Error(fmt.Sprintf("init %v file fail. error info is %s", global.ParameterRecord, err))
		return
	}
	log.MainLog().Info(fmt.Sprintf("Start initializing the Terminal Output file"))
	newTextTPod = outPut.NewFileOperations(outPut.Tex{FileName: fmt.Sprintf("%v/%v.data", baseDir, global.MonitorBarFinishFileName)})
	if err = newTextTPod.Init(); err != nil {
		return
	}
	return
}

func InitGlobalParametersConfig(l *SchemaInitContextConfig) (result *GlobalParametersConfig) {
	var m = l.GtCheckConfig
	return &GlobalParametersConfig{
		repair:  m.SecondaryL.RepairV,
		rules:   m.SecondaryL.RulesV,
		dSns:    m.SecondaryL.DSnsV,
		structs: m.SecondaryL.RulesV.Struct,
		result:  m.SecondaryL.ResultV,
	}
}
func InitCloseObject(m arg.ConfigParameter, result *GlobalParametersConfig) {
	//closeObject = quit.GetClose(map[string]any{
	//	"dsn": map[string]any{"name": m.SecondaryL.DSnsV.DestDBName,
	//		"drive": m.SecondaryL.DSnsV.DestDrive,
	//		"jdbc":  m.SecondaryL.DSnsV.DestJdbc,
	//	},
	//}, p.DDB, []*os.File{result.FilePoint.BreakPointFin, result.FilePoint.ActiveDataFin, result.FilePoint.TtyBarFin, result.FilePoint.ObjectResult})
	global.GetIoc().RegisterContext("closeObject", closeObject)
}

// NewSchedulePlanConfig 初始化全局共享变量
func NewSchedulePlanConfig(l *SchemaInitContextConfig) (result *GlobalParametersConfig, err error) {
	var baseDir = fmt.Sprintf("result/end/%v_%v", l.GtCheckConfig.SecondaryL.RulesV.CheckMode, time.Now().Format("2006-01-02T15-04-05"))
	var event = "[NewSchedulePlanConfig]"
	result = InitGlobalParametersConfig(l)
	if result.db, err = pubM.InitDSnsPool(l.GtCheckConfig); err != nil {
		err = ref.ErrAddPrintf(event, err)
		log.ErrorLog().Error(fmt.Sprintf("create db connection fail. error info is {%s}", err))
		return
	}
	if _, err = pubM.InitResultData(baseDir, l.GtCheckConfig); err != nil {
		err = ref.ErrAddPrintf(event, err)
		log.ErrorLog().Error(fmt.Sprintf("init result datadir fail. error info is {%s}", err))
		return
	}
	if err = initResultData(baseDir, *result); err != nil {
		err = ref.ErrAddPrintf(event, err)
		log.ErrorLog().Error(fmt.Sprintf("init xls result datadir fail. error info is {%s}", err))
		return
	}
	if result.FilePoint, err = initOtherResultFile(baseDir, l.GtCheckConfig.ArgInput.RowsDataCmd.Name, l.GtCheckConfig.ArgInput.RowsDataCmd.Mode, *result); err != nil {
		err = ref.ErrAddPrintf(event, err)
		log.ErrorLog().Error(fmt.Sprintf("init other result datadir fail. error info is {%s}", err))
		return
	}
	if pubM.UpdateModifyParameterSync(result.db.Target, result.FilePoint.ParameterRecord) != nil {
		err = ref.ErrAddPrintf(event, err)
		log.ErrorLog().Error(fmt.Sprintf("update modify parameter fail. error info is {%s}", err))
		return
	}
	InitCloseObject(l.GtCheckConfig, result)
	global.GetIoc().RegisterContext("globalConfig", result)
	return
}
func initSchemaBean(config *SchemaInitContextConfig) (err error) {
	var event = "[initSchemaBean]"
	//注册输入配置
	global.GetIoc().RegisterContext("configParameter", config.GtCheckConfig)
	defer func() {
		if err != nil {
			log.ErrorLog().Error(fmt.Sprintf("%v init plan Config fail. error is {%v}", event, err))
		}
	}()
	//初始化全局共享配置 	//注册执行计划配置 SchedulePlanConfig
	if GlobalPConfigs, err = NewSchedulePlanConfig(config); err != nil || GlobalPConfigs == nil {
		return fmt.Errorf("初始化 NewSchedulePlanConfig 执行计划配置失败 %v", err)
	}
	return
}

// 初始化上下文，该模块的全局配置，过滤表名，按照join、left、unIo方式
func schemaContext(config *SchemaInitContextConfig) *CheckSchemaMetaData {
	var event = "[schemaContext]"
	lock.Lock()
	defer lock.Unlock()
	meta = GetCheckSchemaMetaData()
	meta.ObjectSum = len(config.GtCheckConfig.SecondaryL.TableObject)
	if initSchemaBean(config) != nil {
		close(meta.TableObjectFlow)
		return nil
	}
	fmt.Println(fmt.Sprintf("-- [%v] %v report: begin init table object group -- ", time.Now().Format("2006-01-02 15:04:05"), arg.ToolName))
	log.MainLog().Info(fmt.Sprintf("%v Start checking whether the group table object exists", event))
	go func() {
		defer func() {
			close(meta.TableObjectFlow)
		}()
		if pubM.ObjectExist(pubM.ObjectFlow{
			Drive:     []string{GlobalPConfigs.dSns.SrcDBName, GlobalPConfigs.dSns.DestDBName},
			DriveJoin: "join",
			Source:    GlobalPConfigs.db.Source,
			Target:    GlobalPConfigs.db.Target,
			Mtc:       GlobalPConfigs.rules.Mtc,
			IgnoreSum: &meta.IgnoreObjectSum,
			Object:    config.GtCheckConfig.SecondaryL.TableObject,
			Flow:      meta.TableObjectFlow,
		}) != nil {
			log.MainLog().Error(fmt.Sprintf("%v Failed to initialize table object flow", event))
		}
	}()
	return meta
}
